package net.avcompris.binding.sax.impl;

import static com.avcompris.util.ExceptionUtils.nonNullArgument;

import java.io.IOException;

import net.avcompris.binding.BindConfiguration;
import net.avcompris.binding.impl.AbstractBinder;
import net.avcompris.binding.sax.SAXBinder;
import net.avcompris.binding.sax.Unmarshaller;
import net.avcompris.binding.sax.UnmarshallerFactory;

import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.XMLReaderFactory;

import com.google.common.base.Throwables;

public abstract class AbstractSAXBinder extends AbstractBinder<InputSource>
		implements SAXBinder, UnmarshallerFactory {

	@Override
	protected final <T> T bindInterface(final BindConfiguration configuration,
			final InputSource input, final ClassLoader classLoader,
			final Class<T> clazz) {

		nonNullArgument(configuration, "configuration");
		nonNullArgument(classLoader, "classLoader");
		nonNullArgument(clazz, "clazz");
		nonNullArgument(input, "input");

		final Unmarshaller<T> unmarshaller = createUnmarshaller(configuration,
				classLoader, clazz);

		final XMLReader xmlReader;

		try {

			xmlReader = XMLReaderFactory.createXMLReader();

		} catch (final SAXException e) {

			final Throwable cause = e.getCause();

			Throwables.propagateIfInstanceOf(cause, RuntimeException.class);

			throw new RuntimeException(e);
		}

		xmlReader.setContentHandler(unmarshaller);

		try {

			xmlReader.parse(input);

		} catch (final SAXException e) {

			final Throwable cause = e.getCause();

			Throwables.propagateIfInstanceOf(cause, RuntimeException.class);

			throw new RuntimeException(e);

		} catch (final IOException e) {

			final Throwable cause = e.getCause();

			Throwables.propagateIfInstanceOf(cause, RuntimeException.class);

			throw new RuntimeException(e);
		}

		return unmarshaller.getResult();
	}
}
